/*
  Pachube sensor client
 
 Monitor temperature locally and send it to pachube.com
 
 */

#include <SPI.h>
#include <Ethernet.h>

#include <XBee.h>
//#include <SD.h>

#include "DHT.h"

#define DHTPIN 2     // DHT pin

#define DHTTYPE DHT22   // DHT 22  (Define dht type)

DHT dht(DHTPIN, DHTTYPE);

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 
  0x90, 0xA2, 0xDA, 0x00, 0xF6, 0x3A };

const String pachubeKey = "YIK5TGUIvWxVd87n3y6I0vOZE7d6OwDns6UehPsiNsEfdhTNdaNKDECpLgZ-3eGTCgsU5K8QvXCsmYBt328NLphmie7LlQ5SFEQE0LoVd1dcBejtYLNIGRGymYXaEhZW";

long lastConnectionTime = 0;        // last time you connected to the server, in milliseconds
boolean lastConnected = false;      // state of the connection last time through the main loop
const int postingInterval = 15000;  //delay between updates to Pachube.com

EthernetClient client;

const String _startPayload = "{\"version\":\"1.0.0\",\"datastreams\":[";
const String _endPayload = "]}";

const String _startAirTempDataItemPayload = "{\"id\":\"AiringCupboardTemp\",\"current_value\":\"";
const String _startAirHumDataItemPayload = "{\"id\":\"AiringCupboardHum\",\"current_value\":\"";

const String _startElecTempDataItemPayload = "{\"id\":\"ElecCupboardTemp\",\"current_value\":\"";
const String _startElecHumDataItemPayload = "{\"id\":\"ElecCupboardHum\",\"current_value\":\"";

const String _dataItemDelimiter= ", ";

const String _endDataItemPayload = "\"}";

// xbee
XBee xbee = XBee();
XBeeResponse response = XBeeResponse();
// create reusable response objects for responses we expect to handle 
ZBRxResponse rx = ZBRxResponse();
ModemStatusResponse msr = ModemStatusResponse();

int statusLed = 13;
int errorLed = 13;
int dataLed = 13;


char elecCupboardTempResult[] = {
  0,0,0,0,0,0};
char  elecCupboardHumResult[] = {
  0,0,0,0,0,0};


void setup() {
  pinMode(statusLed, OUTPUT);
  pinMode(errorLed, OUTPUT);
  pinMode(dataLed,  OUTPUT);


  initEthernet();

  xbee.begin(9600);

  dht.begin();
}

void initEthernet()
{
  // Init Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    for(;;)
      delay(100000);
  }

  // give the Ethernet shield a second to initialize:
  delay(1000);
}

void loop()
{
  // if there are incoming bytes available 
  // from the server, read them and print them:
  //while (client.available()) {
  //  char c = client.read();
  //}

  // if there's no net connection, but there was one last time
  // through the loop, then stop the client:
  if (!client.connected() && lastConnected) {
    client.stop();
  }

  // if you're not connected, and x seconds have passed since
  // your last connection, then connect again and send data:
  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    getAndSendData();
  }
  // store the state of the connection for next time through
  // the loop:
  lastConnected = client.connected();

}

void getAndSendData()
{
  xbee.readPacket();

  if (xbee.getResponse().isAvailable()) {
    // got something

    if (setReceivedData()){

      String airCupboardTemp = getTemp();
      String airCupboardHum = getHum();

      if (airCupboardTemp != "F" || airCupboardHum != "F" || elecCupboardTempResult[0] != 'F' || elecCupboardHumResult[0] != 'F')
      { 
        sendData(airCupboardTemp, airCupboardHum, elecCupboardTempResult, elecCupboardHumResult);
      }
    }
  }
}

boolean setReceivedData()
{

  boolean result = false;
  if (xbee.getResponse().getApiId() == ZB_RX_RESPONSE) {
    // got a zb rx packet

    // now fill our zb rx class
    xbee.getResponse().getZBRxResponse(rx);

    if (rx.getOption() == ZB_PACKET_ACKNOWLEDGED) {
      // the sender got an ACK
      flashLed(statusLed, 10, 100);
    } 
    else {
      // we got it (obviously) but sender didn't get an ACK
      flashLed(errorLed, 2, 100);
    }
    // get data from transmission
    for(int i = 0;i<6;i++)
    { 
      elecCupboardTempResult[i] = rx.getData(i); 
    }
    for(int i = 6;i<12;i++)
    { 
      elecCupboardHumResult[i-6] = rx.getData(i); 
    }
    result = true;
  } 
  return result;
}


void sendData(String airCupboardTemp, String airCupboardHum, String elecCupboardTemp, String elecCupboardHum)
{
  // connect to host
  if (client.connect("173.203.98.29", 80)) {
    int totalLength = getPayloadLength(airCupboardTemp, airCupboardHum, elecCupboardTemp, elecCupboardHum);
    totalLength +=2;
    // Make a HTTP request:
    client.println("PUT /v2/feeds/42739 HTTP/1.1");
    client.println("Host: api.pachube.com");         
    client.println("X-PachubeApiKey: " + pachubeKey);

    client.print("Content-Length: ");    
    client.println(String(totalLength));
    client.println("Content-Type: application/json");  
    client.println("Connection: close\n");
    sendPayload(airCupboardTemp, airCupboardHum, elecCupboardTemp, elecCupboardHum);
    client.println();

    lastConnectionTime = millis();
  } 
  else {
    delay(10000);
    client.stop();
  }
}

void sendPayload(String airTemperature, String airHumidity,String elecTemperature, String elecHumidity)
{
  client.print(_startPayload);

  client.print(_startAirTempDataItemPayload);
  client.print(airTemperature);
  client.print(_endDataItemPayload);

  client.print(_dataItemDelimiter);

  client.print(_startAirHumDataItemPayload);
  client.print(airHumidity);
  client.print(_endDataItemPayload);

  client.print(_dataItemDelimiter);

  client.print(_startElecTempDataItemPayload);
  client.print(elecTemperature);
  client.print(_endDataItemPayload);

  client.print(_dataItemDelimiter);

  client.print(_startElecHumDataItemPayload);
  client.print(elecHumidity);
  client.print(_endDataItemPayload);

  client.print(_endPayload);
}

int getPayloadLength(String airTemperature, String airHumidity, String elecTemperature, String elecHumidity)
{
  int totalLength = 0;
  totalLength +=_startPayload.length();

  totalLength += _startAirTempDataItemPayload.length();
  totalLength += airTemperature.length();
  totalLength += _endDataItemPayload.length();

  totalLength +=_dataItemDelimiter.length();

  totalLength += _startAirHumDataItemPayload.length();
  totalLength += airHumidity.length();
  totalLength += _endDataItemPayload.length();

  totalLength += _startElecTempDataItemPayload.length();
  totalLength += elecTemperature.length();
  totalLength += _endDataItemPayload.length();

  totalLength +=_dataItemDelimiter.length();

  totalLength += _startElecHumDataItemPayload.length();
  totalLength += elecHumidity.length();
  totalLength += _endDataItemPayload.length();

  totalLength += _endPayload.length();

  return totalLength;
}

String getTemp()
{
  float t = dht.readTemperature();
  String result = floatToString(t);
  return result;
}

String getHum()
{
  float h = dht.readHumidity();
  String result = floatToString(h);
  return result;
}


String floatToString(float value)
{
  String result;
  char strVal[6]; 
  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (!isnan(value)) {
    dtostrf(value, 2, 2, strVal); //make sure the precision is less than the total chars to avoid an overflow
    result = strVal;
  }
  else {
    result = "F"; // basic error code as result - yuk!  Must learn error handling in C...
  }
  return result;
}

void flashLed(int pin, int times, int wait) {

  for (int i = 0; i < times; i++) {
    digitalWrite(pin, HIGH);
    delay(wait);
    digitalWrite(pin, LOW);

    if (i + 1 < times) {
      delay(wait);
    }
  }
}









